namespace ScrumSprintMonitor.Modules.WorkItemMonitor
{
	#region #using Directives

	using System.Windows.Controls;

	using Extensibility;

	using Infrastructure;
	using Infrastructure.Configuration;

	using Microsoft.Practices.Composite.Modularity;
	using Microsoft.Practices.Composite.Regions;
	using Microsoft.Practices.ServiceLocation;

	using Ninject.Core;
	using Ninject.Core.Behavior;
	using Ninject.Core.Parameters;

	using UI.Wpf.ViewModels;

	using ViewModels;

	#endregion

	[Module(ModuleName = "Work Item Monitor")]
	public class WorkItemMonitorModule : Microsoft.Practices.Composite.Modularity.IModule
	{
		private readonly IKernel kernel;
		private readonly ILogger<WorkItemMonitorModule> logger;
		private readonly IRegionManager regionManager;
		private readonly IResourceManager resourceManager;
		private readonly IServiceLocator serviceLocator;
		private readonly IShellLayoutConfiguration shellLayoutConfiguration;

		public WorkItemMonitorModule(IServiceLocator serviceLocator, IKernel kernel, IRegionManager regionManager, IResourceManager resourceManager,
		                             IShellLayoutConfiguration shellLayoutConfiguration, ILogger<WorkItemMonitorModule> logger)
		{
			this.serviceLocator = serviceLocator;
			this.kernel = kernel;
			this.regionManager = regionManager;
			this.resourceManager = resourceManager;
			this.shellLayoutConfiguration = shellLayoutConfiguration;
			this.logger = logger;

			this.logger.Info("Module starting...");
		}

		#region Implementation of IModule

		public void Initialize()
		{
			RegisterViewsAndServices();

			bool planningMode = this.serviceLocator.GetInstance<IMonitorViewModel>().SprintMode == SprintMode.Planning;

			this.regionManager.RegisterViewWithRegion(RegionNames.PrimaryMonitorRegion, () => this.serviceLocator.GetInstance<IMonitorViewModel>());

			if (this.shellLayoutConfiguration.MultiMonitor || !planningMode)
			{
				this.regionManager.RegisterViewWithRegion(RegionNames.SprintOverviewChartsRegion,
				                                          () => this.serviceLocator.GetInstance<IUserStoryCountChartViewModel>());
				this.regionManager.RegisterViewWithRegion(RegionNames.SprintOverviewChartsRegion,
				                                          () => this.serviceLocator.GetInstance<IBacklogItemCountChartViewModel>());
				this.regionManager.RegisterViewWithRegion(RegionNames.SprintOverviewChartsRegion,
				                                          () => this.serviceLocator.GetInstance<ISprintHoursChartViewModel>());
			}

			this.regionManager.RegisterViewWithRegion(RegionNames.SprintStatisticsRegion, () => this.serviceLocator.GetInstance<ISprintStatsViewModel>());

			this.regionManager.RegisterViewWithRegion(RegionNames.HorizontalSprintTitleRegion,
			                                          () =>
			                                          this.kernel.Get<ISprintTitleViewModel>(With.Parameters.ConstructorArgument("placeholderOrientation",
			                                                                                                                     Orientation.Horizontal)));

			this.regionManager.RegisterViewWithRegion(RegionNames.VerticalSprintTitleRegion,
			                                          () =>
			                                          this.kernel.Get<ISprintTitleViewModel>(With.Parameters.ConstructorArgument("placeholderOrientation",
			                                                                                                                     Orientation.Vertical)));

			if (this.shellLayoutConfiguration.MultiMonitor)
			{
				this.regionManager.RegisterViewWithRegion(RegionNames.SecondaryMonitorRegion, () => this.serviceLocator.GetInstance<ITeamMembersListViewModel>());
			}
			else
			{
				if (planningMode)
				{
					this.regionManager.RegisterViewWithRegion(RegionNames.PrimaryMonitorBottomDockRegion,
					                                          () => this.serviceLocator.GetInstance<ITeamMembersListViewModel>());
				}
				else
				{
					this.regionManager.RegisterViewWithRegion(RegionNames.PrimaryMonitorRightDockRegion,
					                                          () => this.serviceLocator.GetInstance<ITeamMembersListViewModel>());
				}
			}
		}

		#endregion

		protected void RegisterViewsAndServices()
		{
			try
			{
				this.serviceLocator.GetInstance<IMonitorViewModel>();
			}
			catch (Microsoft.Practices.ServiceLocation.ActivationException)
			{
				this.kernel.Load(new MonitorViewModelNinjectModule());
			}

			this.kernel.Load(new WorkItemMonitorNinjectModule());

			if (this.shellLayoutConfiguration.MultiMonitor)
			{
				this.resourceManager.MergeDictionary(
					"pack://application:,,,/ScrumSprintMonitor.Modules.WorkItemMonitor;component/DataTemplates/TeamMembersMonitorDataTemplate.xaml");
			}
			else
			{
				if (this.serviceLocator.GetInstance<IMonitorViewModel>().SprintMode == SprintMode.Planning)
				{
					this.resourceManager.MergeDictionary(
						"pack://application:,,,/ScrumSprintMonitor.Modules.WorkItemMonitor;component/DataTemplates/TeamMembersWrapPanelDataTemplate.xaml");
				}
				else
				{
					this.resourceManager.MergeDictionary(
						"pack://application:,,,/ScrumSprintMonitor.Modules.WorkItemMonitor;component/DataTemplates/TeamMembersVerticalPanelTemplate.xaml");
				}
			}
			this.resourceManager.MergeDictionary(
				"pack://application:,,,/ScrumSprintMonitor.Modules.WorkItemMonitor;component/DataTemplates/PrimaryMonitorDataTemplate.xaml");
			this.resourceManager.MergeDictionary(
				"pack://application:,,,/ScrumSprintMonitor.Modules.WorkItemMonitor;component/DataTemplates/SprintTitleDataTemplate.xaml");
			this.resourceManager.MergeDictionary(
				"pack://application:,,,/ScrumSprintMonitor.Modules.WorkItemMonitor;component/DataTemplates/SprintChartDataTemplate.xaml");
			this.resourceManager.MergeDictionary(
				"pack://application:,,,/ScrumSprintMonitor.Modules.WorkItemMonitor;component/DataTemplates/SprintStatsDataTemplate.xaml");
		}

		#region Nested type: MonitorViewModelNinjectModule

		private class MonitorViewModelNinjectModule : InlineModule
		{
			public MonitorViewModelNinjectModule()
				: base(m => m.Bind<IMonitorViewModel>().To<MonitorViewModel>().Using<SingletonBehavior>())
			{
			}
		}

		#endregion

		#region Nested type: WorkItemMonitorNinjectModule

		private class WorkItemMonitorNinjectModule : InlineModule
		{
			public WorkItemMonitorNinjectModule()
				: base(
					m => m.Bind<ITeamMembersListViewModel>().To<TeamMembersListViewModel>().Using<SingletonBehavior>(),
					m => m.Bind<ITeamMemberViewModel>().To<TeamMemberViewModel>(),
					m => m.Bind<IUserStoryCountChartViewModel>().To<UserStoryCountChartViewModel>().Using<SingletonBehavior>(),
					m => m.Bind<IBacklogItemCountChartViewModel>().To<BacklogItemCountChartViewModel>().Using<SingletonBehavior>(),
					m => m.Bind<ISprintTitleViewModel>().To<SprintTitleViewModel>(),
					m => m.Bind<ISprintStatsViewModel>().To<SprintStatsViewModel>().Using<SingletonBehavior>(),
					m => m.Bind<ISprintHoursChartViewModel>().To<SprintHoursChartViewModel>().Using<SingletonBehavior>())
			{
			}
		}

		#endregion
	}
}